/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

import { EventEmitter } from 'events';

import { CoreTask } from '../../../external/task/core-task.js';
import { noop } from '../../../../common/util/noop.js';
import { Priority } from '../enum/priority.js';
import { TaskState, transitionMap } from '../enum/task-state.js';
import { SubmitOption } from '../worker-pool/submit-option.js';

import { TCB } from './tcb.js';
import { Work } from './work.js';

/**
 * 内部任务控制块
 * 任务控制块接口的实现类
 *
 * @since 2022/8/12
 */
export class ITCB extends EventEmitter implements TCB {
  private workerId: number | undefined;
  private readonly submitTime: number;
  private startTime: number | undefined;
  private endTime: number | undefined;
  private state: TaskState;
  private work: Work;
  private cb: Function;
  private cbInput: unknown[];
  private readonly updateLoc: Function;
  private readonly taskPath: string;
  private readonly taskName: string;
  private readonly taskCompletePath: string;
  private readonly useRetVal: boolean;
  private readonly warmUp: boolean;

  constructor(
    work: Work,
    callback: Function,
    useRetVal: boolean | undefined,
    cbInput: unknown[],
    updateLoc: Function,
    taskPath: string,
    taskName: string,
    taskCompletePath: string,
    warmUp = false,
    state?: TaskState,
  ) {
    super();
    this.work = work;
    this.cb = callback;
    this.cbInput = cbInput;
    this.submitTime = Date.now();
    this.updateLoc = updateLoc;
    this.taskPath = taskPath;
    this.taskName = taskName;
    this.taskCompletePath = taskCompletePath;
    this.state = state ?? TaskState.WAITING;
    this.useRetVal = useRetVal ?? false;
    this.warmUp = warmUp;
  }

  /**
   * 当work不允许在WorkerPool中执行时,需要返回一个TaskState为reject的默认TCB
   *
   * @param {CoreTask} task
   * @param {Work} work
   * @param {SubmitOption} submitOption
   * @return {TCB}
   */
  static getDefaultRejectTcb(task: CoreTask, work: Work, submitOption?: SubmitOption): TCB {
    return new ITCB(work, noop, submitOption?.useReturnVal, [], noop, task.getNode().getName(), task.getName(), task.getPath(), false, TaskState.REJECT);
  }

  getId(): string {
    return this.work.getId();
  }

  getWorkerId(): number | undefined {
    return this.workerId;
  }

  getSubmitTime(): number {
    return this.submitTime;
  }

  getStartTime(): number | undefined {
    return this.startTime;
  }

  getEndTime(): number | undefined {
    return this.endTime;
  }

  getState(): TaskState {
    return this.state;
  }

  getPriority(): Priority {
    return this.work.getPriority();
  }

  getCallback(): Function {
    return this.cb;
  }

  getCallbackInput(): unknown[] {
    return this.cbInput;
  }

  /**
   * 设置workerId
   *
   * @param workerId 待设置的workerId
   */
  setWorkerId(workerId: number): void {
    this.workerId = workerId;
  }

  setState(state: TaskState): boolean {
    if (transitionMap.get(this.state)?.has(state)) {
      this.state = state;
      return true;
    }
    return false;
  }

  /**
   * 设置优先级
   *
   * @param priority 待设置的优先级
   * @returns {boolean} 是否设置成功
   */
  setPriority(priority: Priority): boolean {
    if (this.state === TaskState.WAITING) {
      this.work.setPriority(priority);
      this.updateLoc();
      return true;
    }
    return false;
  }

  setCallback(callback: Function, callbackInput?: unknown[]): boolean {
    if (this.state === TaskState.WAITING || this.state === TaskState.RUNNING) {
      this.cb = callback;
      this.cbInput = callbackInput ?? this.cbInput;
      return true;
    }
    return false;
  }

  /**
   * 设置开始时间
   *
   * @param startTime 开始时间
   */
  setStartTime(startTime: number): void {
    this.startTime = startTime;
  }

  /**
   * 设置结束时间
   *
   * @param endTime 结束时间
   */
  setEndTime(endTime: number): void {
    this.endTime = endTime;
  }

  getTaskCompletePath(): string {
    return this.taskCompletePath;
  }

  getTaskName(): string {
    return this.taskName;
  }

  getTaskPath(): string {
    return this.taskPath;
  }

  useReturnVal(): boolean {
    return this.useRetVal;
  }

  /**
   * 是否是预热任务
   *
   * @returns {boolean} 判断结果
   */
  isWarmUp(): boolean {
    return this.warmUp;
  }
}
